CodeDeployとCircleCIを利用したBlue/Greenデプロイメント
はじめに
こんにちは、中山です。
今回CircleCIとCodeDeployを組み合わせてイミュータブルなBlue/Greenデプロイ環境を作ってみました。内容的には以下のエントリを組み合わせたものになります。
- [公式チュートリアルではじめる]CircleCI+CodeDeployを使ったCD(継続的デプロイ)
- TerraformとCodeDeployでイミュータブルなBlue/Greenデプロイ環境を構築する
- TerraformのコードをCircleCI経由でデプロイさせる
構成図
デプロイの流れが異なるのでDevとOpsで構成図を分けました。今回説明を簡略化させるためにDev用コード(CodeDeploy)、Ops用コード(Terraform)を混ぜていますが、本番環境では別リポジトリに分離して管理することをオススメします。
Devの場合
Devの場合のデプロイフローは以下のとおりです。
- コードの修正後GitHubに
git push
- Web HookでCircleCIに通知
circle.yml
の中でリビジョンのアップロードとCodeDeployの実行
Dev用のブランチには以下の2つを利用します。
release/blue
: Blueリリース用ブランチrelease/green
: Greenリリース用ブランチ
今回テスト目的なので、リリースブランチのみにします。つまりアプリケーションのテストは含めていません。
circle.yml
の内容は以下のとおりです。
<snip> deployment: blue: branch: release/blue codedeploy: bg-deploy-app: application_root: /app revision_location: revision_type: S3 s3_location: bucket: bg-deploy-app key_pattern: apps/{SHORT_COMMIT} region: ap-northeast-1 deployment_group: Blue deployment_config: CodeDeployDefault.AllAtOnce green: branch: release/green codedeploy: bg-deploy-app: application_root: /app revision_location: revision_type: S3 s3_location: bucket: bg-deploy-app key_pattern: apps/{SHORT_COMMIT} region: ap-northeast-1 deployment_group: Green deployment_config: CodeDeployDefault.AllAtOnce <snip>
release/blue
または release/green
ブランチにプッシュされたらデプロイが実行されます。CodeDeployの設定内容(詳細はドキュメント参照)は以下のとおりです。
設定 | 内容 |
---|---|
codedeploy |
CircleCIでCodeDeployの設定をする際に指定します。 |
bg-deploy-app |
CodeDeployのアプリケーション名です。 |
application_root |
appspec.yml の設置場所です。リポジトリのトップディレクトリからの相対パスを指定します。少しハマったのですが、先頭のスラッシュは必須です。 |
revision_location |
リビジョンの設定です。 |
revision_type |
リビジョンの保管場所です。現時点ではS3のみサポートされています。 |
s3_location |
以降の設定でリビジョンを保存するS3バケットの場所を指定します。 |
bucket |
リビジョンを保存するバケット名を指定します。 |
key_pattern |
リビジョンを保存するS3バケットのキー名を指定します。ここにはいろいろと変数を指定可能です。 {SHORT_COMMIT} はコミットハッシュ値のショートバージョンが参照できます。 |
region |
そのまんまリージョンです。 |
deployment_group |
そのまんまデプロイメントグループ名です。 |
deployment_config |
どうやってデプロイするかを指定します。 |
Opsの場合
Opsの場合のデプロイフローは以下のとおりです。
- コードの修正後GitHubに
git push
- Web HookでCircleCIに通知
circle.yml
の中でTerraformの実行
Ops用のブランチには以下の2つを利用します。
ops
: 開発用ブランチrelease/ops
: リリース用ブランチ
circle.yml
については、以前のエントリに書いたので割愛します。
コード
GitHubに置いときました。ご自由にお使いください。
実行方法
GitHubとCircleCIとの連携など、初期セットアップは以下のエントリを参照してください。
以下の手順では初期セットアップはすでに導入済みで、Blue環境がASGの下にぶら下がっているという前提で進めます。
Blueへのデプロイ
まず素の状態で動作しているBlueに対してデプロイしてセットアップしましょう。今回はデプロイ自体を目的にしているので、空コミットでプッシュします。Blueのデプロイメントグループに対してデプロイしたいので、ブランチを release/blue
に切り替えて作業してください。
$ git checkout -b release/blue Switched to a new branch 'release/blue' $ git commit -m 'Deploy blue' --allow-empty [release/blue 66d1f2d] Deploy blue $ git push origin release/blue Counting objects: 1, done. Writing objects: 100% (1/1), 185 bytes | 0 bytes/s, done. Total 1 (delta 0), reused 0 (delta 0) To https://github.com/knakayama/blue-green-deployment-with-codedeploy-and-circleci.git be42e77..66d1f2d release/blue -> release/blue
デプロイに成功後、ELBのエンドポイントにアクセスすると以下の画面が表示されます。
作業完了後、masterブランチに結果を反映しておきます。
$ git checkout master Switched to branch 'master' $ git merge --no-ff release/blue Already up-to-date! Merge made by the 'recursive' strategy.
Greenへのデプロイ
続いてGreenへデプロイします。先程と同じようにまずブランチを切って作業を実施します。Green用リリースブランチは release/green
です。
$ git checkout -b release/green Switched to a new branch 'release/green'
続いて app/index.html
を以下のように修正してください。
$ git diff diff --git a/app/index.html b/app/index.html index de45436..5e9c4db 100644 --- a/app/index.html +++ b/app/index.html @@ -5,11 +5,11 @@ <style type="text/css"> body { - background-color: #00FFFF; + background-color: #00FF00; } </style> </head> <body> - <h1>This is Blue v1.0.</h1> + <h1>This is Green v1.0.</h1> </body> </html>
コミット後、プッシュします。
$ git add app/index.html $ git commit -m 'Deploy green' [release/green 52e6355] Deploy green 1 file changed, 2 insertions(+), 2 deletions(-) $ git push origin release/green Counting objects: 5, done. Delta compression using up to 4 threads. Compressing objects: 100% (5/5), done. Writing objects: 100% (5/5), 611 bytes | 0 bytes/s, done. Total 5 (delta 2), reused 0 (delta 0) To https://github.com/knakayama/blue-green-deployment-with-codedeploy-and-circleci.git 6558892..52e6355 release/green -> release/green
念のためGreenサーバにSSHでログインして確認します。以下のように表示されたらOKです。
$ ssh -i keys/key_pair ec2-user@<public-ip> 'curl -fsSL localhost' <!DOCTYPE html> <html> <head> <title>Blue</title> <style type="text/css"> body { background-color: #00FF00; } </style> </head> <body> <h1>This is Green v1.0.</h1> </body> </html>
ELBの切り替え
この時点では、ELBの向き先がBlueになっています。これを切り替えます。Terraformのコードは ops
ブランチでテスト可能です。まずはここでテストしてみます。以下のコマンドを実行してブランチを切り替えてください。
# masterは最新の状態にしたいのでrelease/greenをマージ $ git checkout master Switched to branch 'master' $ git merge --no-ff release/green Merge made by the 'recursive' strategy. app/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) # masterからブランチを切る $ git checkout -b ops Switched to a new branch 'ops'
modules/asg/blue/blue.tf
と modules/asg/green/green.tf
をそれぞれ以下のように修正してください。
$ git diff diff --git a/modules/asg/blue/blue.tf b/modules/asg/blue/blue.tf index c1e20e0..b470338 100644 --- a/modules/asg/blue/blue.tf +++ b/modules/asg/blue/blue.tf @@ -8,14 +8,14 @@ resource "aws_autoscaling_group" "blue" { health_check_grace_period = 300 health_check_type = "ELB" force_delete = true - load_balancers = ["${var.load_balancer_id}"] + + #load_balancers = ["${var.load_balancer_id}"] tag { key = "Name" value = "Blue" propagate_at_launch = true } - lifecycle { create_before_destroy = true } diff --git a/modules/asg/green/green.tf b/modules/asg/green/green.tf index afcda96..262e856 100644 --- a/modules/asg/green/green.tf +++ b/modules/asg/green/green.tf @@ -8,14 +8,14 @@ resource "aws_autoscaling_group" "green" { health_check_grace_period = 300 health_check_type = "ELB" force_delete = true - - #load_balancers = ["${var.load_balancer_id}"] + load_balancers = ["${var.load_balancer_id}"] tag { key = "Name" value = "Green" propagate_at_launch = true } + lifecycle { create_before_destroy = true
修正したらコミット後、 ops
ブランチにプッシュします。
$ git add modules $ git commit -m 'Change ELB' [ops 29420fb] Change ELB 2 files changed, 4 insertions(+), 4 deletions(-) $ git push origin ops
成功するとCircleCIの画面で以下のように表示されます。
テストに成功したので実際にデプロイしましょう。リリースは release/ops
ブランチで実施します。
$ git checkout -b release/ops Switched to a new branch 'release/ops' $ git push origin release/ops Total 0 (delta 0), reused 0 (delta 0) To https://github.com/knakayama/blue-green-deployment-with-codedeploy-and-circleci.git * [new branch] release/ops -> release/ops
デプロイに成功後、ELBのエンドポイントにアクセスすると以下が画面が表示されます。
まとめ
いかがだったでしょうか。
CodeDeployとCircleCIを組み合わせてBlue/Greenデプロイを作成してみました。CircleCIのようなCIサービスを使いこなして、チーム内でデプロイ作業を安全に行いたいですね。もっと触ってみようと思います。
本エントリがみなさんの参考になれば幸いです。